#include "hex.h"

#include <string.h>
#include "esp_log.h"
#include "esp_system.h"
#include "esp_mac.h"
#include <lwip/inet.h>
#include <lwip/sockets.h>
#include <lwip/netdb.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

char *TAG = "hex";

int numberOfLeadingZeros(int i) {
        // HD, Figure 5-6
		int n = 1;
        if (i == 0)
            return 32;
        if (i >> 16 == 0) { n += 16; i <<= 16; }
        if (i >> 24 == 0) { n +=  8; i <<=  8; }
        if (i >> 28 == 0) { n +=  4; i <<=  4; }
        if (i >> 30 == 0) { n +=  2; i <<=  2; }
        n -= i >> 31;
        return n;
}

/** INT 类型转字节码 */
void int2Bytes(int integer,char *byteArray) {
		int n=0;
		int byteNum = (40 - numberOfLeadingZeros(integer < 0 ? ~integer : integer)) / 8;
		for (n = 0; n < byteNum; n++)
			byteArray[3 - n] = (char) (integer >> (n * 8));
}
/** 字节转INT类型 **/
static int mbytes2Int(char *b, int offset) {
	int value = 0,i=0;
	for(i = 0; i < 4; i++) {
		int shift = (4 - 1 - i) * 8;
		value += (b[i + offset] & 0x000000FF) << shift;
	}
	return value;
}

/** 字节转INT类型
 * @param b			4位字节
 * **/
int bytes2Int(char *b) {
	return mbytes2Int(b, 0);
}

/** 字符串分割
 * @param src 		源字符串
 * @param separator 字符串分隔符
 * @param dest		分割结果
 * @param num		结果长度
 * */
void split(char *src, const char *separator, char **dest, int *destnum) {
	char *pNext;
	int count = 0;

	if (src == NULL || strlen(src) == 0)
		return;
	if (separator == NULL || strlen(separator) == 0)
		return;

	pNext = strtok(src, separator);

	while (pNext != NULL) {
		*dest++ = pNext;
		++count;
		pNext = strtok(NULL, separator);
	}

	*destnum = count;
}

/** 字符串截取 长度小于256
 * @param src 		源字符串
 * @param start 	开始索引
 * @param end 		结束索引
 * */
char* substr(const char*str, unsigned start, unsigned end){
    unsigned n = end - start;
    static char stbuf[256];
    strncpy(stbuf, str + start, n);
    stbuf[n] = 0; //字串最后加上0
    return stbuf;
}

// 截取字符串
int SubString2(char *string_out, char *string_in, unsigned start_index, unsigned end_index){
	unsigned n = end_index - start_index;
	char *stbuf = NULL;
	MallocBuf(char,stbuf,n + 1);
	strncpy(stbuf, string_in + start_index, n);
	stbuf[n] = 0; //字串最后加上0
	memcpy_s(string_out,n,stbuf,n);
	FreeBuf(stbuf);
	return n;
}

/** 获取当前路径
 * @param void  无参数
 * @return 		返回路径
 */
char *GetCntPath(void){
	char *file_path_getcwd;
    file_path_getcwd=(char *)malloc(256);
	memset(file_path_getcwd,0,256);
#ifdef _WIN32
	_getcwd(file_path_getcwd,256);
#else
	getcwd(file_path_getcwd,256);
#endif
    
 //   printf("%s",file_path_getcwd);
    return file_path_getcwd;
}

/** 删除左边的空格
 * @param szOutput 输出
 * @param szInput  输入
 */
char * l_trim(char * szOutput, const char *szInput) {
	assert(szInput != NULL);
	assert(szOutput != NULL);
	assert(szOutput != szInput);
	for (; *szInput != '\0' && isspace(*((unsigned char *)szInput)); ++szInput) {
		;
	}
	return strcpy(szOutput, szInput);
}

/** 删除右边的空格
 * @param szOutput 输出
 * @param szInput  输入
 */
char *r_trim(char *szOutput, const char *szInput) {
	char *p = NULL;
	assert(szInput != NULL);
	assert(szOutput != NULL);
	assert(szOutput != szInput);
	strcpy(szOutput, szInput);
	for (p = szOutput + strlen(szOutput) - 1; p >= szOutput && isspace(*((unsigned char *)p));
			--p) {
		;
	}
	*(++p) = '\0';
	return szOutput;
}

/** 删除两边的空格
 * @param szOutput 输出
 * @param szInput  输入
 */
char * a_trim(char * szOutput, const char * szInput) {
	char *p = NULL;
	assert(szInput != NULL);
	assert(szOutput != NULL);
	l_trim(szOutput, szInput);
	for (p = szOutput + strlen(szOutput) - 1; p >= szOutput && isspace(*((unsigned char *)p));--p) {
		;
	}
	*(++p) = '\0';
	return szOutput;
}


/** 检索字符串str中第一个出现char c的位置
 * @param 	str 	字符串
 * @param 	c   	字符
 * @return   	 	返回数组下标,没有则返回-1
 **/
int Indexof(char *str, char c) {
	int result = -1, len = 0, i = 0;
	len = strlen(str);
	for (i = 0; i < len; i++) {
		if (str[i] == c) {
			result = i;
			break;
		}
	}
	return result;
}

/** 检索字符串str中最后一个个出现char c的位置
 * @param 	str 	字符串
 * @param 	c   	字符
 * @return   	 	返回数组下标,没有则返回-1
 **/
int LastIndexOfChar(char *str, char c) {
	int result = -1, len = 0, i = 0;
	len = strlen(str);
	for (i = len - 1; i >= 0; i--) {
		if (str[i] == c) {
			result = i;
			break;
		}
	}
	return result;
}

/** 检索字符串str1中第一个出现str2 c的位置
 * @param 	str 	字符串
 * @param 	c   	字符
 * @return   	 	返回数组下标,没有则返回-1
 **/
int IndexOf(char *str1,char *str2)  
{  
	char *p=str1;  
	int i=0;  
	p=strstr(str1,str2);
	if(p==NULL)  
		return -1;  
	else{  
		while(str1!=p)  
		{  
			str1++;  
			i++;  
		}  
	}  
	return i;  
}  

/** 检索字符串str1从fromIndex开始算起第一个出现str2 c的位置
* @param 	str1 	字符串
* @param 	str2 	字符串
* @param 	fromIndex 	int
 * @return   	 	返回数组下标,没有则返回-1
 **/
int IndexOfFrom(char *str1,char *str2, int fromIndex) {
	char *p=str1;  
	int i=0;
	if(strlen(str1) - (fromIndex < 0?0:fromIndex) <= 0) return -1;
	p=strstr(str1 + fromIndex,str2);
	if(p==NULL)  
		return -1;  
	else{  
		while(str1!=p)  
		{  
			str1++;  
			i++;  
		}  
	}  
	return i;  
}

char* SubString(const char*str, unsigned start, unsigned end){
	return substr(str,start,end);
}
/** 检索字符串str1中第一个出现str2 c的位置
 * @param 	str 	字符串
 * @param 	c   	字符
 * @return   	 	返回数组下标,没有则返回-1
 **/
int LastIndexOf(char *str1,char *str2)  
{  
	char *p=str1;  
	int i=0,len=strlen(str2);  
	p=strstr(str1,str2);  
	if(p==NULL)return -1;  
	while(p!=NULL)  
	{  
		for(;str1!=p;str1++)i++;  
		p=p+len;  
		p=strstr(p,str2);  
	}  
	return i;  
}  
/** 替换字符串中特征字符串为指定字符串
 * @param 		sSrc		源字符串
 * @param 		sMatchStr	匹配字符串
 * @param 		sReplaceStr	匹配结果
 * @return 		int			无匹配则返回-1
 **/
int ReplaceStr(char *sSrc, char *sMatchStr, char *sReplaceStr) {
	int StringLen;
	char caNewString[1024];
	char *FindPos = strstr(sSrc, sMatchStr);
	if ((!FindPos) || (!sMatchStr))
		return -1;
	while (FindPos) {
		memset(caNewString, 0, sizeof(caNewString));
		StringLen = FindPos - sSrc;
		strncpy(caNewString, sSrc, StringLen);
		strcat(caNewString, sReplaceStr);
		strcat(caNewString, FindPos + strlen(sMatchStr));
		strcpy(sSrc, caNewString);
		FindPos = strstr(sSrc, sMatchStr);
	}
	return 0;
}

//判断是否是".."目录和"."目录
 int is_special_dir(const char *path)
{
	return strcmp(path, "..") == 0 || strcmp(path, ".") == 0;
}

//判断文件属性是目录还是文件
 int is_dir(int attrib)
{
#ifdef _WIN32
	return attrib == 16 || attrib == 18 || attrib == 20;
#else
//	struct stat statbuf;
//	if(lstat(path, &statbuf) ==0)//lstat返回文件的信息，文件信息存放在stat结构中
//	{
//		return S_ISDIR(statbuf.st_mode) != 0;//S_ISDIR宏，判断文件类型是否为目录
//	}
	return 0;
#endif
}

 //判断文件属性是目录还是文件
 int CheckPathIsDir(char *path){
#ifdef WIN32
	 struct _stat buf; 
	 int result; 
	 result = _stat( path, &buf ); 
	 if(_S_IFDIR & buf.st_mode){ 
		 return 1;
	 }else if(_S_IFREG & buf.st_mode){ 
		// printf("file\n"); 
	 }
#endif
	 return 0;
 }
 
//字节流转换为十六进制字符串
void ByteToHexStr(const unsigned char* source, char* dest, int sourceLen)
{
#ifdef __APPLE__
    base64_encode((unsigned char *)source, sourceLen, dest);
#else
    unsigned short i;
    unsigned char highByte, lowByte;
    
    for (i = 0; i < sourceLen; i++)
    {
        highByte = source[i] >> 4;
        lowByte = source[i] & 0x0f ;
        
        highByte += 0x30;
        
        if (highByte > 0x39)
            dest[i * 2] = highByte + 0x07;
        else
            dest[i * 2] = highByte;
        
        lowByte += 0x30;
        if (lowByte > 0x39)
            dest[i * 2 + 1] = lowByte + 0x07;
        else
            dest[i * 2 + 1] = lowByte;
    }
#endif
	
	return ;
}

//十六进制字符串转换为字节流
void HexStrToByte(const char* source, unsigned char* dest, int sourceLen)
{
#ifdef __APPLE__
    base64_decode(source, sourceLen, (unsigned char *)dest);
#else
    short i;
    unsigned char highByte, lowByte;
    
    for (i = 0; i < sourceLen; i += 2)
    {
        highByte = toupper(source[i]);
        lowByte  = toupper(source[i + 1]);
        
        if (highByte > 0x39)
            highByte -= 0x37;
        else
            highByte -= 0x30;
        
        if (lowByte > 0x39)
            lowByte -= 0x37;
        else
            lowByte -= 0x30;
        
        dest[i / 2] = (highByte << 4) | lowByte;
    }
    return ;
#endif
    
	
}

int Random(int ran){
	int nRet = 0; 
	srand((int)time(0));
	nRet = (rand()%ran);
	return nRet;
}

/**
 * 将域名解析为IP地址（优先返回IPv4）
 * @param ip_buffer 存储解析后的IP地址（输入缓冲区需至少16字节）
 * @param domain 待解析的域名
 * @return 成功返回0，失败返回错误码
 */
int GetHostByName(unsigned char *ip_buffer, unsigned char *domain) {
   

    struct addrinfo hints = {0};
    struct addrinfo *res = NULL, *ai = NULL;
    int err = 0;

	 if (!ip_buffer || !domain) {
        return -1; // 输入参数无效
    }

    // 配置hints结构体，优先解析IPv4
    hints.ai_family = AF_UNSPEC;     // 允许IPv4或IPv6
    hints.ai_socktype = SOCK_STREAM; // TCP类型

	ESP_LOGD(TAG,"domain: %s",domain);
    // 执行域名解析
    err = getaddrinfo((const char *)domain, NULL, &hints, &res);
    if (err != 0) {
        ESP_LOGE("DNS", "域名解析失败: %s", strerror(err));
        return err;
    }

    // 遍历结果，优先提取IPv4地址
    for (ai = res; ai != NULL; ai = ai->ai_next) {
        if (ai->ai_family == AF_INET) { // IPv4地址
            struct sockaddr_in *ipv4 = (struct sockaddr_in *)ai->ai_addr;
            inet_ntop(AF_INET, &(ipv4->sin_addr), (char *)ip_buffer, INET_ADDRSTRLEN);
            break;
        } else if (ai->ai_family == AF_INET6 && ip_buffer) { // IPv6地址
            struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)ai->ai_addr;
            inet_ntop(AF_INET6, &(ipv6->sin6_addr), (char *)ip_buffer, INET6_ADDRSTRLEN);
            // 继续查找，优先使用IPv4
        }
    }

    // 释放资源
    freeaddrinfo(res);

    // 检查是否找到IP地址
    if (ai == NULL) {
        ESP_LOGE("DNS", "未找到匹配的IP地址");
        return -2; // 未找到IP地址
    }

    return 0; // 成功
}


unsigned long long fn_GetSystemTime() {
	return (unsigned long long)xTaskGetTickCount() * portTICK_PERIOD_MS;
}